package com.zq.mycloud.gateway.handler;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.zq.mycloud.core.respones.GeneralResult;
import com.zq.mycloud.core.consts.ErrorCodeConstant;
import com.zq.mycloud.gateway.exception.CommonException;
import com.zq.mycloud.gateway.util.I18nUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.server.*;
import org.springframework.web.server.ResponseStatusException;

import java.net.ConnectException;
import java.net.UnknownHostException;
import java.util.Map;

/**
 * @author ：zhang qiang
 * @package :com.zq.mycloud.gateway.handler
 * @date ：Created in 2020/12/11 下午3:27
 * @description：全局异常处理方案
 * @modified By：
 * @version: $
 */
@Slf4j
public class GlobalExceptionHandler extends DefaultErrorWebExceptionHandler {

    public GlobalExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties, ErrorProperties errorProperties, ApplicationContext applicationContext) {
        super(errorAttributes, resourceProperties, errorProperties, applicationContext);
    }

    /**
     * 获取异常属性
     */
    @Override
    protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean options) {
        Throwable error = super.getError(request);
        // 按照异常类型进行处理
        GeneralResult<Object> generalResult = new GeneralResult<Object>();
        Route route = (Route) request.exchange().getAttributes().get(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
        String routeId = route == null ? "" : route.getId();
        if (error instanceof CommonException) {
            generalResult.setMessage(error.getMessage());
            generalResult.setCode(((CommonException) error).getCode());
            generalResult.setMsg(((CommonException) error).getMsg());
        } else if (error instanceof ResponseStatusException) {
            HttpStatus responseStatus = ((ResponseStatusException) error).getStatus();
            if (responseStatus == HttpStatus.NOT_FOUND) {
                String message = I18nUtil.translateCode(ErrorCodeConstant.URL_NOT_FOUND, request.exchange().getRequest().getPath(), routeId);
                generalResult.setMessage(message);
                generalResult.setMsg(error.getMessage());
                generalResult.setCode(ErrorCodeConstant.URL_NOT_FOUND);
            } else {
                String message = I18nUtil.translateCode(ErrorCodeConstant.REQUESTED_SERVICE_INTERNAL_ERROR, routeId);
                generalResult.setMessage(message);
                generalResult.setMsg(error.getMessage());
                generalResult.setCode(ErrorCodeConstant.REQUESTED_SERVICE_INTERNAL_ERROR);
            }
        } else if (error instanceof UnknownHostException) {
            String message = I18nUtil.translateCode(ErrorCodeConstant.INTERNAL_SERVICE_ADDRESS_ERROR, routeId);
            generalResult.setMessage(message);
            generalResult.setMsg(error.getMessage());
            generalResult.setCode(ErrorCodeConstant.INTERNAL_SERVICE_ADDRESS_ERROR);
        } else if (error instanceof ConnectException) {
            String message = I18nUtil.translateCode(ErrorCodeConstant.CONNECT_SERVER_ERROR, routeId);
            generalResult.setMessage(message);
            generalResult.setMsg(error.getMessage());
            generalResult.setCode(ErrorCodeConstant.CONNECT_SERVER_ERROR);
        } else {
            String message = I18nUtil.translateCode(ErrorCodeConstant.REQUESTED_SERVICE_INTERNAL_ERROR, routeId);
            generalResult.setMessage(message);
            generalResult.setMsg(error.getMessage());
            generalResult.setCode(ErrorCodeConstant.REQUESTED_SERVICE_INTERNAL_ERROR);
        }
        return JSONObject.parseObject(JSONObject.toJSONString(generalResult, SerializerFeature.WriteMapNullValue), Map.class);
    }

    /**
     * 指定响应处理方法为JSON处理的方法
     *
     * @param errorAttributes
     */
    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
    }

    /**
     * 根据code获取对应的HttpStatus
     *
     * @param errorAttributes
     */
    @Override
    protected int getHttpStatus(Map<String, Object> errorAttributes) {

        //int statusCode = (int) errorAttributes.get("code");
        //定义不都为正常返回
        return HttpStatus.OK.value();
    }

}
